<template>
  <el-dialog
    class="custom-dialog no-pdding-dialog"
    v-model="dialogVisible"
    title="定位"
    width="720px"
    @close="handleClose"
  >
    <div class="main-container one-map">
      <div class="latlngbox" v-show="!addAddress">
        <span class="text">经度：{{ mousePositionLatLng.longitude }}</span>
        <span class="text">纬度：{{ mousePositionLatLng.latitude }}</span>
        <span class="text">位置：{{ location }}</span>
      </div>
      <div class="choose_btn" v-if="!disabled">
        <el-button type="primary" @click="onSubmit">确定</el-button>
        <el-button class="clear" @click="clearLocation">清除</el-button>
      </div>
      <MapboxMap
        :map-id="mapId"
        @after-map-loaded="afterMapLoaded"
        @before-map-destroyed="beforeMapDestroyed"
      />
    </div>
  </el-dialog>
</template>
<script setup>
import { onBeforeMount, reactive, ref, createApp, h, inject, watch } from 'vue'
import { debounce, remove } from 'lodash'
import { ElMessage } from 'element-plus'
import mapboxgl, { LngLat } from 'mapbox-gl'
import MapboxMap from '@/components/mapbox-map.vue'
import { jsonp } from '@/utils/jsonp/index.js'
import { nanoid } from 'nanoid'
import * as coordtransform from 'coordtransform'
import LocationInfoPopup from '@/components/location-info-popup.vue'

// const location = ref("");
const props = defineProps({
  disabled: {
    type: Boolean,
    default: false,
  },
  latlnt: {
    type: String,
    default: () => '',
  },
  addAddress: {
    type: Boolean,
    default: false,
  },
  areaStr: {
    type: String,
    default: () => '',
  },
  deviceLocation: {
    type: String,
    default: '',
  },
})

const mapId = nanoid()

const MAP_KEY = 'LW6BZ-EA6C5-4DDI6-QCZLB-UEOVZ-JUBVV'

let _map
let _marker
let _popup

let markers = []

/**
 * 鼠标位置经纬度
 */
const mousePositionLatLng = reactive({
  latitude: '',
  longitude: '',
})

const location = ref('')

const afterMapLoaded = async (id, map) => {
  if (props.addAddress) {
    map.on('click', onMarkerClick)
  } else {
    map.on('click', onMapClick)
  }
  _map = map
  if (props.addAddress) {
    if (props.latlnt) {
      const points = JSON.parse(props.latlnt)
      if (points) {
        initMarkers(points)
      }
    }
  } else {
    initMousePosition()
  }
  areaShow()
  resizeMap()
}

const beforeMapDestroyed = (id, map) => {
  // console.log("before map destroy:", id, map);
  if (props.addAddress) {
    markers = []
    map.off('click', onMarkerClick)
  } else {
    map.off('click', onMapClick)
  }
}
const resizeMap = () => {
  setTimeout(() => {
    _map?.resize()
  })
}

const onMarkerClick = (event) => {
  // 这种点击方式一定是添加多个点，创建marker和弹窗
  if (_map && !props.disabled) {
    // 不用考虑更新的问题，只存在删除，所以直接创建
    addMarker(event.lngLat)
  }
}

/**
 * 初始化鼠标位置参数
 */
const initMousePosition = () => {
  const mapCenter = _map.getCenter()
  // console.log(props, "props");
  let latlnt = props.latlnt ? props.latlnt?.split(',') : null
  mousePositionLatLng.longitude = latlnt ? latlnt[0] : mapCenter.lng.toFixed(6)
  mousePositionLatLng.latitude = latlnt ? latlnt[1] : mapCenter.lat.toFixed(6)
  if (_map && latlnt) {
    _map.setCenter([parseFloat(latlnt[0]), parseFloat(latlnt[1])])
    const point = new LngLat(parseFloat(latlnt[0]), parseFloat(latlnt[1]))
    addPoint(point)
  }
}

const communityArea = ''

const areaShow = () => {
  if (communityArea) {
    if (communityArea.value) {
      const arr = JSON.parse(communityArea.value)
      if (_map && arr.length) {
        let jsonLine = {
          type: 'FeatureCollection',
          features: [],
        }
        arr.map((item, index) => {
          let point = [item]
          jsonLine.features.push({
            type: 'Feature',
            properties: {},
            geometry: {
              type: 'Polygon',
              coordinates: point,
            },
          })
          if (index == 0) {
            _map.setCenter(point[0][0])
          }
        })
        // console.log(jsonLine);
        _map.addSource('line-area', {
          type: 'geojson',
          data: jsonLine,
        })
        _map.addLayer({
          id: 'line-area',
          type: 'fill',
          source: 'line-area',
          paint: {
            'fill-color': 'rgb(0,255,0)',
            'fill-opacity': 0.5,
            'fill-outline-color': 'rgb(0,0,0)',
          },
        })
      }
    }
  }
}

const updatePosition = (latlnt) => {
  if (props.addAddress) return
  if (latlnt) {
    const arr = JSON.parse(latlnt)
    const point = new LngLat(parseFloat(arr[0]), parseFloat(arr[1]))
    mousePositionLatLng.latitude = point.lat
    mousePositionLatLng.longitude = point.lng
    location.value = arr[2]
    if (_marker) {
      _marker.setLngLat(point)
      _popup.setLngLat(point)
    } else {
      addPoint(point)
    }
  } else {
    const mapCenter = _map.getCenter()
    mousePositionLatLng.latitude = mapCenter.lat
    mousePositionLatLng.longitude = mapCenter.lng
    location.value = '渝中区重庆医科大学附属儿童医院8号楼'
    if (_marker) {
      _marker.setLngLat(mapCenter)
      _popup.setLngLat(mapCenter)
    } else {
      addPoint(mapCenter)
    }
    areaShow()
  }
}

const deletePopup = () => {
  _marker.remove()
  _popup.remove()
  _popup = null
  _marker = null
}

/**
 * 地图点击事件
 *
 * @param {mapboxgl.MapMouseEvent} event 鼠标事件
 */
const onMapClick = (event) => {
  if (_map && !props.disabled) {
    getMouseLatLnt(event)
  }
}

const deleteMarker = (id) => {
  const item = markers.find((val) => val.id == id)
  if (item) {
    const { marker, popup } = item
    marker.remove()
    popup.remove()
    remove(markers, item)
  }
}

const getMarker = () => {
  const center = document.createElement('div')
  const el = document.createElement('div')

  center.style.width = '16px'
  center.style.height = '16px'
  center.style.backgroundColor = '#00BAFF'
  center.style.borderRadius = '50%'
  center.style.border = '2px solid white'
  el.style.width = '84px'
  el.style.height = '84px'
  el.style.background = 'rgba(0,186,255,.2)'
  el.style.borderRadius = '50%'
  el.style.display = 'flex'
  el.style.justifyContent = 'center'
  el.style.alignItems = 'center'
  el.appendChild(center)

  return new mapboxgl.Marker(el)
}

const getPopup = (pointInfo, address, id, deleteMarker) => {
  const template = createApp(LocationInfoPopup, {
    pointInfo,
    address,
    id,
    deleteMarker: deleteMarker,
    disabled: props.disabled,
  })
  const div = document.createElement('div')
  template.mount(div)
  return new mapboxgl.Popup({
    anchor: 'bottom',
    closeOnClick: false,
    closeButton: false,
    offset: [0, -10],
    className: 'marker',
    maxWidth: '120px',
  }).setDOMContent(div)
}

const addMarker = async (lngLat, addressStr) => {
  if (_map) {
    const lng = lngLat.lng.toFixed(6)
    const lat = lngLat.lat.toFixed(6)
    let address = ''
    if (addressStr) {
      address = addressStr
    } else {
      address = await getAddress(lng, lat)
    }
    const id = nanoid()
    const popup = getPopup([lng, lat], address, id, deleteMarker)
    popup.setLngLat(lngLat).addTo(_map)

    const marker = getMarker().setLngLat(lngLat).addTo(_map)
    markers.push({
      point: [lng, lat],
      id,
      address,
      popup,
      marker,
    })
  }
}

const initMarkers = (points) => {
  if (_map) {
    let arr = points
    if (!Array.isArray(points[0])) {
      arr = [points]
    }
    arr.forEach((point) => {
      const lngLat = new LngLat(point[0], point[1])
      addMarker(lngLat, point[2])
    })
  }
}

const addPoint = (lngLat) => {
  if (_map) {
    if (!location.value) {
      getAddress(
        mousePositionLatLng.longitude,
        mousePositionLatLng.latitude,
      ).then((address) => {
        location.value = address
      })
    }
    _marker = getMarker().setLngLat(lngLat).addTo(_map)
    _popup = getPopup(mousePositionLatLng, location, '', deletePopup)
    _popup.setLngLat(lngLat).addTo(_map)
  }
}

/**
 * 清除坐标
 */
const clearLocation = () => {
  if (props.addAddress) {
    markers.forEach((marker) => {
      marker.popup.remove()
      marker.marker.remove()
    })
    markers = []
  } else {
    _marker?.remove()
    _marker = null
    _popup?.remove()
    _popup = null
  }
}

const emit = defineEmits(['submitLocation'])

const onSubmit = () => {
  if (props.addAddress) {
    // console.log(location.value);
    let points = ''
    if (markers && markers.length) {
      points = markers.map((item) => {
        return [...item.point, item.address]
      })
    }
    emit('submitLocation', points)
  } else {
    emit('submitLocation', mousePositionLatLng)
  }
}

const getAddress = async (lng, lat) => {
  const [l1, l2] = coordtransform.wgs84togcj02(lng, lat)
  const url = `https://apis.map.qq.com/ws/geocoder/v1/?location=${l2},${l1}&key=${MAP_KEY}&get_poi=0`
  return new Promise((resolve, reject) => {
    jsonp(url, { output: 'jsonp' })
      .then((res) => {
        if (res.status === 0) {
          const { formatted_addresses } = res.result
          if (formatted_addresses) {
            resolve(formatted_addresses.recommend)
          } else {
            resolve('')
          }
        } else {
          resolve('')
        }
      })
      .catch((err) => {
        reject(err)
      })
  })
}

const getMouseLatLnt = debounce(function (event) {
  const lng = event.lngLat.lng.toFixed(6)
  const lat = event.lngLat.lat.toFixed(6)
  mousePositionLatLng.longitude = lng
  mousePositionLatLng.latitude = lat

  if (_marker) {
    _marker.setLngLat(event.lngLat)
    _popup.setLngLat(event.lngLat)
  } else {
    addPoint(event.lngLat)
  }
}, 100)

const dialogVisible = defineModel('dialogVisible')
const handleClose = () => {
  dialogVisible.value = false
}

watch(
  () => props.deviceLocation,
  (val) => {
    if (val) {
      location.value = val
    }
  },
)

defineExpose({ updatePosition, resizeMap })
</script>

<style lang="scss" scoped>
.one-map {
  position: relative;
  overflow: hidden;
  // padding: 13px;

  .latlngbox {
    height: 48px;
    background: #000000;
    opacity: 0.5;
    position: absolute;
    top: 13px;
    right: 13px;
    left: 13px;
    z-index: 99;
    text-align: center;

    .text {
      font-size: 14px;
      font-weight: bold;
      color: #ffffff;
      line-height: 48px;
      margin-right: 20px;
    }
  }

  .choose_btn {
    position: absolute;
    right: 30px;
    top: 76px;
    z-index: 99;
    display: flex;
    flex-direction: column;

    .el-button {
      width: 110px;
      height: 42px;
      margin: 0 0 17px 0;
      font-size: 18px;
      font-weight: 400;
      border-radius: 2px;
    }

    .clear {
      color: #fa3434;
      border: 1px solid #fa3434;
      background-color: transparent;
      background: rgba(255, 255, 255, 0.15);
    }
  }

  .mapbox-map {
    width: 100%;
    height: 600px;
  }

  :deep(.mapboxgl-marker) {
    top: -15px;
  }
}
</style>
